package com.jt808.decode.utils;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Message body packaging
 * @date 2023-11-09
 */
@Slf4j
public class BuildMessageBody {
    /**
     * package the setting(0x8103) command message body
     * @param params
     * @return
     */
    public static byte[] build8103MessageBody(LinkedHashMap<Integer,Object> params){
        try{
            //Number of parameters
            int paramCount=params.size();
            //The number of parameters needs to be added by 1 byte
            int bodyLen=getBodyLen(params)+1;
            ByteBuf msgBody = Unpooled.buffer(bodyLen);
            msgBody.writeByte(paramCount);
            for(Integer key: params.keySet()){
                //Parameter ID takes up 4 bytes+parameter length is 1 byte
                msgBody.writeInt(key);
                switch (key){
                    case 0x0001:
                    case 0x0018:
                    case 0x0027:
                    case 0x0029:
                    case 0x0030:
                    case 0x0055:
                    case 0x0056:
                    case 0x0080:
                    case 0xF005:
                    case 0xF018:
                    case 0xF01D:
                    case 0xF01E:
                    case 0xF022:
                    case 0xF028:
                    case 0xF02B:
                    case 0xF02E:
                    case 0xF02F:
                        msgBody.writeByte(4);
                        msgBody.writeInt(Integer.parseInt(String.valueOf(params.get(key))));
                        break;
                    case 0x0010:
                    case 0x0011:
                    case 0x0012:
                    case 0x0013:
                    case 0x0017:
                    case 0xF000:
                    case 0xF004:
                    case 0xF030:
                        byte[] paramArr= String.valueOf(params.get(key)).getBytes();
                        msgBody.writeByte(paramArr.length);
                        msgBody.writeBytes(paramArr);
                        break;
                    case 0xF001:
                    case 0xF002:
                    case 0xF003:
                    case 0xF00E:
                    case 0xF013:
                    case 0xF015:
                    case 0xF01C:
                    case 0xF021:
                    case 0xF024:
                    case 0xF025:
                    case 0xF026:
                    case 0xF027:
                        msgBody.writeByte(2);
                        msgBody.writeShort(Integer.parseInt(String.valueOf(params.get(key))));
                        break;
                    case 0xF006:
                    case 0xF007:
                    case 0xF008:
                    case 0xF009:
                    case 0xF00A:
                    case 0xF00B:
                    case 0xF00C:
                    case 0xF00D:
                    case 0xF00F:
                    case 0xF010:
                    case 0xF011:
                    case 0xF012:
                    case 0xF014:
                    case 0xF016:
                    case 0xF017:
                    case 0xF019:
                    case 0xF01A:
                    case 0xF01B:
                    case 0xF01F:
                    case 0xF020:
                    case 0xF023:
                    case 0xF029:
                    case 0xF02A:
                    case 0xF02C:
                    case 0xF02D:
                        msgBody.writeByte(1);
                        msgBody.writeByte(Integer.parseInt(String.valueOf(params.get(key))));
                        break;
                    default:
                        break;
                }
            }
            byte[] msgBodyArr = msgBody.array();
            ReferenceCountUtil.release(msgBody);
            return msgBodyArr;
        }catch (Exception e){
            log.error("build8103MessageBody:{}",params,e);
            return null;
        }
    }

    /**
     * package the device control(0x8105) command message body
     * @param params
     * @return
     */
    public static byte[] build8105MessageBody(Map<Integer,Object> params){
        try{
            byte [] paramArr=null;
            Integer key = params.keySet().stream().findFirst().get();
            switch (key) {
                case 32:
                    Map<String, String> mapParam = JSONObject.parseObject(params.get(key).toString(), new TypeReference<Map<String, String>>(){});
                    String strUpgrade="";
                    if (mapParam.containsKey("MD5")) {
                        //TYPE; MODE; VERSION; PROTOCOL; URL; MD5
                        strUpgrade = String.format("%s;%s;%s;%s;%s;%s",mapParam.get("TYPE"),mapParam.get("MODE"),mapParam.get("VERSION"),mapParam.get("PROTOCOL"),mapParam.get("URL"),mapParam.get("MD5"));
                    } else {
                        //TYPE; MODE; VERSION; PROTOCOL; URL;123456
                        strUpgrade = String.format("%s;%s;%s;%s;%s;%s", mapParam.get("TYPE"),mapParam.get("MODE"),mapParam.get("VERSION"),mapParam.get("PROTOCOL"),mapParam.get("URL"),"123456");
                    }
                    paramArr=strUpgrade.getBytes();
                    break;
                case 33:
                case 34:
                case 0x85:
                case 0x86:
                case 0x87:
                case 0x88:
                    paramArr=new byte[1];
                    paramArr[0]=(byte)Integer.parseInt(String.valueOf(params.get(key)));
                case 36:
                    paramArr= String.valueOf(params.get(key)).getBytes();
                    break;
                case 35:
                    Map<String, String> map35Param = JSONObject.parseObject(params.get(key).toString(), new TypeReference<Map<String, String>>(){});
                    String strOutput = String.format("%s,%s", map35Param.get("CHANNEL"), map35Param.get("MODE"));
                    paramArr= strOutput.getBytes();
                    break;
                default:
                    break;
            }
            int bodyLen=0;
            if(paramArr!=null){
                bodyLen=paramArr.length+1;
            }else{
                bodyLen=1;
            }
            ByteBuf msgBody = Unpooled.buffer(bodyLen);
            msgBody.writeByte(key);
            if(bodyLen>1) {
                msgBody.writeBytes(paramArr);
            }
            byte[] msgBodyArr = msgBody.array();
            ReferenceCountUtil.release(msgBody);
            return msgBodyArr;
        }catch (Exception e){
            log.error("build8105MessageBody:{}",params,e);
            return null;
        }
    }

    /**
     * package Downlink Transparent Transmission (0x8300) command message body
     * @param params
     * @return
     */
    public static byte[] build8300MessageBody(Map<Integer,Object> params){
        try{
            //透传类型
            Integer key = params.keySet().stream().findFirst().get();
            //透传数据
            String message = params.get(key).toString();
            byte [] messageArr=message.getBytes();
            ByteBuf msgBody = Unpooled.buffer(messageArr.length+1);
            msgBody.writeByte(key);
            msgBody.writeBytes(messageArr);
            byte[] msgBodyArr = msgBody.array();
            ReferenceCountUtil.release(msgBody);
            return msgBodyArr;
        }catch (Exception e){
            log.error("build8300MessageBody:{}",params,e);
            return null;
        }
    }

    /**
     * package Downlink Transparent Transmission (0x8900) command message body
     * @param params
     * @return
     */
    public static byte[] build8900MessageBody(Map<Integer,Object> params){
        try{
            //透传类型
            Integer key = params.keySet().stream().findFirst().get();
            //透传数据
            String message = params.get(key).toString();
            byte [] messageArr=message.getBytes();
            ByteBuf msgBody = Unpooled.buffer(messageArr.length+1);
            msgBody.writeByte(key);
            msgBody.writeBytes(messageArr);
            byte[] msgBodyArr = msgBody.array();
            ReferenceCountUtil.release(msgBody);
            return msgBodyArr;
        }catch (Exception e){
            log.error("build8900MessageBody:{}",params,e);
            return null;
        }
    }

    /**
     * package Platform RSA Public Key (0x8A00) command message body
     * @param params
     * @return
     */
    public static byte[] build8A00MessageBody(Map<String,Object> params){
        try{
            //透传类型
            String key = params.keySet().stream().findFirst().get();
            byte[] keyArr= ByteBufUtil.decodeHexDump(key);
            //透传数据
            String value = params.get(key).toString();
            byte[] valueArr= ByteBufUtil.decodeHexDump(value);
            ByteBuf msgBody = Unpooled.buffer(keyArr.length+valueArr.length);
            msgBody.writeBytes(keyArr);
            msgBody.writeBytes(valueArr);
            byte[] msgBodyArr = msgBody.array();
            ReferenceCountUtil.release(msgBody);
            return msgBodyArr;
        }catch (Exception e){
            log.error("build8A00MessageBody:{}",params,e);
            return null;
        }
    }

    /**
     * Message body length
     * @param params
     * @return
     */
    private static int getBodyLen(LinkedHashMap<Integer,Object> params){
        int bodyLen=0;
        for(Integer key: params.keySet()){
            //Parameter ID takes up 4 bytes+parameter length is 1 byte
            bodyLen+=5;
            switch (key){
                case 0x0001:
                case 0x0018:
                case 0x0027:
                case 0x0029:
                case 0x0030:
                case 0x0055:
                case 0x0056:
                case 0x0080:
                case 0xF005:
                case 0xF018:
                case 0xF01D:
                case 0xF01E:
                case 0xF022:
                case 0xF028:
                case 0xF02B:
                case 0xF02E:
                case 0xF02F:
                    bodyLen+=4;
                    break;
                case 0x0010:
                case 0x0011:
                case 0x0012:
                case 0x0013:
                case 0x0017:
                case 0xF000:
                case 0xF004:
                case 0xF030:
                    byte[] paramArr= String.valueOf(params.get(key)).getBytes();
                    bodyLen+=paramArr.length;
                    break;
                case 0xF001:
                case 0xF002:
                case 0xF003:
                case 0xF00E:
                case 0xF013:
                case 0xF015:
                case 0xF01C:
                case 0xF021:
                case 0xF024:
                case 0xF025:
                case 0xF026:
                case 0xF027:
                    bodyLen+=2;
                    break;
                case 0xF006:
                case 0xF007:
                case 0xF008:
                case 0xF009:
                case 0xF00A:
                case 0xF00B:
                case 0xF00C:
                case 0xF00D:
                case 0xF00F:
                case 0xF010:
                case 0xF011:
                case 0xF012:
                case 0xF014:
                case 0xF016:
                case 0xF017:
                case 0xF019:
                case 0xF01A:
                case 0xF01B:
                case 0xF01F:
                case 0xF020:
                case 0xF023:
                case 0xF029:
                case 0xF02A:
                case 0xF02C:
                case 0xF02D:
                    bodyLen+=1;
                    break;
                default:
                    break;
            }
        }
        return bodyLen;
    }
}
